package drds.binlog.database_driver.packets;

import drds.binlog.common.Authors;
import drds.common.Author;
import lombok.Getter;
import lombok.Setter;

/**
 * <pre>
 * Offset  Length     Description
 *   0       3        Packet body length stored with the low byte first.
 *   3       1        Packet sequence number. The sequence numbers are reset with each new command.
 *                      While the correct packet sequencing is ensured by the underlying transmission protocol,
 *                      this field is used for the sanity checks of the application logic.
 * </pre>
 * <p>
 * <br>
 * The Packet Header will not be shown in the descriptions of packets that
 * follow this section. Think of it as always there. But logically, it
 * "precedes the packet" rather than "is included in the packet".<br>
 */
@Author(name = Authors.LI_YANG)
public class HeaderPacket implements Packet
{

    /**
     * this field indicates the packet length that follows the headerPacket, with
     * headerPacket packet's 4 bytes excluded.
     */
    @Setter
    @Getter
    private int packetBodyLength;
    @Setter
    @Getter
    private byte packetSequenceNumber;

    /**
     * little-endian byte order
     */
    public byte[] toBytes()
    {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (packetBodyLength & 0xFF);
        bytes[1] = (byte) (packetBodyLength >>> 8);
        bytes[2] = (byte) (packetBodyLength >>> 16);
        bytes[3] = getPacketSequenceNumber();
        return bytes;
    }

    /**
     * little-endian byte order
     */
    public void fromBytes(byte[] bytes)
    {
        if (bytes == null || bytes.length != 4)
        {
            throw new IllegalArgumentException("invalid headerPacket data. It can't be null and the length must be 4 byte.");
        }
        this.packetBodyLength = (bytes[0] & 0xFF) | ((bytes[1] & 0xFF) << 8) | ((bytes[2] & 0xFF) << 16);
        this.setPacketSequenceNumber(bytes[3]);
    }


}
